// Copyright (C) 2023 即时通讯网(52im.net) & Jack Jiang.
// The RainbowChat Project. All rights reserved.
// 
// 【本产品为著作权产品，合法授权后请放心使用，禁止外传！】
// 【本次授权给：<北京小羊驼科技有限公司>，授权编号：<NT231212144350>，代码指纹：<A.702363430.550>，技术对接人微信：<ID: wxid_wbyootvkdcgj22>】
// 【授权寄送：<收件：苏先生、地址：北京市大兴区北京密码西区6号楼1单元301、电话：18613885610、邮箱：bd@huiyuanxiang-inc.com>】
// 
// 【本系列产品在国家版权局的著作权登记信息如下】：
// 1）国家版权局登记名(简称)和权证号：RainbowChat    （证书号：软著登字第1220494号、登记号：2016SR041877）
// 2）国家版权局登记名(简称)和权证号：RainbowChat-Web（证书号：软著登字第3743440号、登记号：2019SR0322683）
// 3）国家版权局登记名(简称)和权证号：RainbowAV      （证书号：软著登字第2262004号、登记号：2017SR676720）
// 4）国家版权局登记名(简称)和权证号：MobileIMSDK-Web（证书号：软著登字第2262073号、登记号：2017SR676789）
// 5）国家版权局登记名(简称)和权证号：MobileIMSDK    （证书号：软著登字第1220581号、登记号：2016SR041964）
// * 著作权所有人：江顺/苏州网际时代信息科技有限公司
// 
// 【违法或违规使用投诉和举报方式】：
// 联系邮件：jack.jiang@52im.net
// 联系微信：hellojackjiang
// 联系QQ号：413980957
// 授权说明：http://www.52im.net/thread-1115-1-1.html
// 官方社区：http://www.52im.net
package com.x52im.rbchat.logic.chat_guest;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;

import com.eva.android.ArrayListObservable;
import com.eva.android.ObserverMain;
import com.eva.android.ToolKits;
import com.eva.android.widget.WidgetUtils;
import com.x52im.rbchat.Const;
import com.x52im.rbchat.R;
import com.x52im.rainbowchat.im.dto.ChatType;
import com.x52im.rainbowchat.im.dto.MsgType;
import com.x52im.rbchat.logic.alarm.AlarmType;
import com.x52im.rbchat.logic.chat_friend.utils.MessageForwardHelper;
import com.x52im.rbchat.logic.chat_guest.utils.TMessageForwardHelper;
import com.x52im.rbchat.logic.chat_root.AbstractChattingActivity;
import com.x52im.rbchat.logic.chat_root.targetchoose.TargetChooseActivity;
import com.x52im.rbchat.logic.chat_root.face.FaceBoardView;
import com.x52im.rbchat.logic.chat_root.impl.AbstractMoreUIWrapper;
import com.x52im.rbchat.logic.chat_root.impl.UnreadMessageBallonWrapper;
import com.x52im.rbchat.logic.chat_guest.utils.TMessageReSendHelper;
import com.x52im.rbchat.logic.chat_root.AbstractChattingListAdapter;
import com.x52im.rbchat.logic.chat_root.sendfile.SendFileHelper;
import com.x52im.rbchat.logic.chat_root.model.Message;
import com.x52im.rbchat.logic.chat_root.sendimg.SendImageWrapper;
import com.x52im.rbchat.logic.chat_root.sendvoice.SendVoiceDialog;
import com.x52im.rbchat.logic.chat_guest.utils.TMessageHelper;
import com.x52im.rbchat.logic.chat_root.targetchoose.TargetSource;
import com.x52im.rbchat.logic.chat_root.targetchoose.TargetSourceFilterFactory;
import com.x52im.rbchat.logic.sns_friend.impl.SendFriendReqUIWrapper;
import com.x52im.rbchat.network.http.bigfile.BigFileUploadManager;
import com.x52im.rbchat.permission2.PermissionManager;
import com.x52im.rbchat.utils.ActivityRequestCode;
import com.x52im.rbchat.utils.IntentFactory;
import com.x52im.rbchat.utils.PreferencesToolkits;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Observable;
import java.util.Observer;

import androidx.core.app.ActivityCompat;

/**
 * 陌生人（临时）聊天界面实现类。
 *
 * @author json.zhao, Jiang Jiang(http://www.52im.net/space-uid-1.html)
 * @since 2.1
 */
public class TempChattingActivity extends AbstractChattingActivity {

	//=============================================================== 标准聊天相关
	/** 按钮：发送语音留言消息 */
	private Button btnSendVoice;
	/** 按钮：发送文本消息 */
	private Button btnSend;
	/** 按钮：打开输入框下方的"更多功能"面板  */
	private Button btnOpenPlusFunctions;
	/** 按钮：返回 */
	private Button btnBack = null;
	/** 按钮：查看陌生人信息 */
	private Button btnMore = null;
	/** 标签组件：消息输入 */
	private EditText txtMsg;

	/** 文本组件：好友昵称 */
	private TextView viewNickName;
	/** 文本组件：“陌生人”标题文本 */
	private TextView viewTitleHint;
	/** 图标组件：界面标题后面的静音图标 */
	private ImageView viewSilentIco;
	
	/** 聊天消息列表 */
	private ListView listView;
	/** 聊天消息列表adapter */
	private TempChattingListAdapter listAdapter;
    /** 当消息列表最后一行处于可见或不可见时的新消息（未读消息）提示ui包装实现类. */
    private UnreadMessageBallonWrapper unreadMessageBallonWrapper = null;
	
	/** 聊天界面的根面板 */
	private LinearLayout layoutChattingRoot = null;
	
	/** 输入框左边功能：发送图片包装实现对象 */
	private SendImageWrapper menuWindowForSendPic = null;
	/** 输入框左边功能：发送语音留言对话框 */
	private SendVoiceDialog sendVoiceDialog = null;
	
	/** “更多“功能父布局 */
	private FrameLayout layoutbottomContent = null;
	/** "更多"功能gridview UI封装类 */
	private AbstractMoreUIWrapper tempMoreUIWrapper = null;

	/** FFF 表情按钮及面板 */
	private Button btnOpenFace;
	private FaceBoardView faceBoardView;

	/** 
	 * <p>
	 * 列表的全局数据结构对对象.<br>
	 * 为什么要做成静态全局变量呢？目的是：使得本activity在程序的生命周期中，都能保持上一次的查询结果（省
	 * 得每次从本activity回退或退出后都重新实例化列表数据模型从而使用户体验不佳——查询功能就是为了方便查看，有时候退出
	 * 并不想清空数据的哦（比如：想去核对一下某个单据中的数据等）），本对象的静态全局化仅为此服务，没无其它目的。
	 * </p>
	 */
	private ArrayListObservable<Message> chattingDatas = null;
    /** 数据模型变动观察者实现block */
    private ObserverMain chattingDatasObserver = null;

	// FIXME: 此变量因历史原因而存在，未来将逐步统一由父类中的toId替代之，本变量将在以后版本中弃用
	/** @deprecated by super.toId */
	private String tempChatUIDForInit = null;
	// FIXME: 此变量因历史原因而存在，未来将逐步统一由父类中的toName替代之，本变量将在以后版本中弃用
	/** @deprecated by super.toName */
	private String tempChatFriendName = null;
	private int tempChatMaxFriendForInit = 0;

	//=============================================================== 大文件发送相关 START
	/**
	 * 设置{@link BigFileUploadManager}中大文件任务状态改变观察者(主要用于“我”发送的大文件消息)，
	 * 用于UI及时刷新大文件上传状态在界面上的显示（本观察者通常由对应的UI界面设置，界面退到后台消失时取消设置） */
	private ObserverMain fileStatusChangedObserver = createFileStatusChangedObserver();
	//=============================================================== 大文件发送相关 END

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.chatType = ChatType.CHAT_TYPE_GUEST$CHAT;
		super.onCreate(savedInstanceState);
	}

	/**
	 * 根据Activity的生命周期：本Activity每次从后台回到前台时调用本方法。
	 */
	protected void onResume() {
		super.onResume();

		// 及时根据设置的"消息免打扰"，刷新ui显示
		this.viewSilentIco.setVisibility(!PreferencesToolkits.isChatMsgToneOpen(this, tempChatUIDForInit)?View.VISIBLE:View.GONE);

		// 设置当前正处于激话状态下的聊时聊天好友uid
		imc().setCurrentFrontTempChattingUserUID(tempChatUIDForInit);
		// 设置大文件上传状态变更观察者(主要用于“我”发送的大文件消息)
		imc().getBigFileUploadManager().setFileStatusChangedObserver(fileStatusChangedObserver);
		// APP中唯一重置未读临时聊天消息的代码：最后确保重置APP首页“消息”未读消息数字的显示
		imc().getAlarmsProvider().resetFlagNum(AlarmType.guestChat, tempChatUIDForInit, 0, true);
	}
	
	/**
	 * 根据Activity的生命周期：本Activity每次从前台退到后台时调用本方法。
	 */
	protected void onPause() {
		super.onPause();
		// 取消设置当前正处于激话状态下的临时聊天好友uid
		imc().setCurrentFrontTempChattingUserUID(null);
		// 取消设置大文件上传状态变更观察者(主要用于“我”发送的大文件消息)
		imc().getBigFileUploadManager().setFileStatusChangedObserver(null);

		// 如果真在进行语音留言录制的话就hide它
		if(sendVoiceDialog != null)
			sendVoiceDialog.hide();
	}
	
	/**
	 * 本activity被销毁时额外要做一些事.
	 */
	@Override
	protected void onDestroy() {
		// 如果真在进行语音留言录制的话就销毁它
		if(sendVoiceDialog != null)
			sendVoiceDialog.dismiss();
		// 释放ListAdapter中需要释放的资源
		if(listAdapter != null)
			listAdapter.forParentDestraoy();
        // 逆初始化：释放资源
        deInitToGuest(tempChatUIDForInit);
		super.onDestroy();
	}

	/**
	 * {@inheritDoc}
	 */
	@Override
	protected void initDataFromIntent() {
		super.initDataFromIntent();

		ArrayList datas = IntentFactory.parseTempChatIntent(getIntent());
		tempChatUIDForInit = (String)datas.get(0);
		tempChatFriendName = (String)datas.get(1);
		tempChatMaxFriendForInit = (Integer)datas.get(2);//CommonUtils.getIntValue((String)datas.get(3), 1);

		super.toId = this.tempChatUIDForInit;
		super.toName = this.tempChatFriendName;
	}

	/**
	 * 本方法由父类的onCreate()调用，子类可在此方法中实现自已的UI显示逻辑。
	 */
	@Override
	protected void initViews(Bundle savedInstanceState) {
		super.initViews(savedInstanceState);

		// 养成良好习惯：首先设置主layout，确保后绪的操作中使用到的组件都可以被find到
		setContentView(R.layout.temp_chatting_list_view);

		// 各功能组件
		txtMsg = (EditText) this.findViewById(R.id.temp_chatting_list_view_msgEdit);
		btnSendVoice = (Button) this.findViewById(R.id.temp_chatting_list_view_sendVoiceBtn);
		btnSend = (Button) this.findViewById(R.id.temp_chatting_list_view_sendBtn);
		btnOpenPlusFunctions = (Button) this.findViewById(R.id.temp_chatting_list_view_plusBtn);
		viewNickName = (TextView) this.findViewById(R.id.temp_chatting_list_view_nickNameView);
		btnBack = (Button) this.findViewById(R.id.temp_chatting_list_view_backBtn);
		btnMore = (Button) this.findViewById(R.id.temp_chatting_list_view_seeMoreBtn);
		viewTitleHint = (TextView) this.findViewById(R.id.temp_chatting_list_view_titleHintView);
		viewSilentIco = (ImageView) this.findViewById(R.id.temp_chatting_list_view_silentIconView);

		// 列表及列表的adapter
		listView = (ListView) findViewById(R.id.temp_chatting_list_view_listView);
		// 初始化消息列表及列表的adapter
		initListViewAndAdapter();
		
		// 聊天界面的根面板
		layoutChattingRoot = (LinearLayout)this.findViewById(R.id.chatting_list_view_rootLL);
		// 输入框下方的功能区父布局
		layoutbottomContent = (FrameLayout)this.findViewById(R.id.temp_chatting_list_view_bottomContentFL);
		// 实例化发送图片包装实现类
		menuWindowForSendPic = new SendImageWrapper(this, layoutChattingRoot, tempChatUIDForInit, Const.CHAT_TYPE_GUEST$CHAT);
		
		// 输入框下方的更多功能
		this.initChatFunctionsUI();
		// FFF 表情按钮及面板
		this.initFaceUI();
		// 根据Intent中传过来的好友信息数据，切换到与该好友的聊天
		this.initToGuest();
	}

	/**
	 * 为各UI功能组件增加事件监听的实现方法. 默认情况下本方法什么也不做，子类需自行实现之.
	 */
	protected void initListeners() {
		//** 为以下组件添加点击查看好友信息的事件处理(进入聊天信息界面)
		OnClickListener lisToSeeFriendInfo = v -> startActivity(IntentFactory.createChatInfoIntent(self(), tempChatUIDForInit, this.viewNickName.getText().toString()));
		viewNickName.setOnClickListener(lisToSeeFriendInfo);
		viewTitleHint.setOnClickListener(lisToSeeFriendInfo);
		btnMore.setOnClickListener(lisToSeeFriendInfo);
		
		//** 消息输入框左边的语音留言按钮事件处理
		btnSendVoice.setOnClickListener(v -> {
			if(checkIsMyFriend())
				return;

			// 开始动态权限申请（用于targetSDKVersion>=23，即Android6.0及以上系统时）
			PermissionManager.requestPermission_RECORD_AUDIO(self()
					// 权限获取成功或已经取得此权限时
					, (o, arg) -> {
						//** 权限正常获取，继续走正常的代码逻辑。。。

						// 消息列表首先自动滚动到最后一行
						listAdapter.showLastItem();
						// 把句柄缓存起来，以便 下次打开时能快一点（经实测，跟每次都new SendVoiceDialog，确实要快很多哦！）
						if(sendVoiceDialog == null)
							sendVoiceDialog = new SendVoiceDialog(self(), tempChatUIDForInit, Const.CHAT_TYPE_GUEST$CHAT);
						// 显示之
						sendVoiceDialog.show();
					}
					, null);
		});
		
		//**　文本消息发送按钮事件处理
		btnSend.setOnClickListener(v -> {
			if(checkIsMyFriend())
				return;
			sendPlainTextMessage((observable, data) -> txtMsg.setText(""));
		});

		//** 标题栏的返回按钮事件处理
		btnBack.setOnClickListener(v -> TempChattingActivity.this.finish());
		
		//** 加为好友的按钮事件处理
        OnClickListener addFriendLis = v -> SendFriendReqUIWrapper.sendAddFriendRequestWidthDialog(self()
				, tempChatUIDForInit, tempChatFriendName, tempChatMaxFriendForInit);
        // 列表顶部提示信息上的加好友按钮
        ((Button)this.findViewById(R.id.temp_chatting_list_view_hint_addFriendBtn)).setOnClickListener(addFriendLis);
		
		//** 初始化输入框下方的”更多“功能按钮、面板等事件处理逻辑
		initChatFunctionsLisnter();

        //** 长按弹出菜单事件注册和处理逻辑
		super.initListViewListenersImpl(this, listView, listAdapter);
	}
	
	/**
	 * 初始化消息列表及列表的adapter。
	 */
	private void initListViewAndAdapter() {
		// 生成适配器的ImageItem <====> 动态数组的元素，两者一一对应
		if(chattingDatas == null)//先实例化列表的全局数据结构对对象（如果已经实例化了就不需要现新那对 象了，目的是为了保留上次的数据）
			chattingDatas = new ArrayListObservable<>();

        // 初始化当消息列表最后一行处于可见或不可见时的新消息（未读消息）提示ui包装实现对象
        unreadMessageBallonWrapper = new UnreadMessageBallonWrapper(this, R.id.temp_chatting_list_view_unreadBallonBtn){
            /**
             * 当点击未读气泡时要调用的方法.
             */
            @Override
            protected void fireOnClickBallon() {
                // 点击未读气泡时自动让消息列表滚动到最后一行
                if(listAdapter != null)
                    listAdapter.showLastItem();
            }
        };
		
		listAdapter = new TempChattingListAdapter(this, listView, tempChatUIDForInit);
		listView.setAdapter(listAdapter);
	}

	private void initFaceUI() {
		btnOpenFace = this.findViewById(R.id.temp_chatting_list_view_openFaceBtn);
		faceBoardView = this.findViewById(R.id.i_faceboard);
		faceBoardView.setInputEt(txtMsg); // 绑定输入框

		// 表情面板的事件处理（出于通用目的，暂时只有OnOperationListener事件被提炼到父类中）
		super.initFaceListenersImpl(this, faceBoardView, txtMsg);

		// 表情面板显示后要做的事：消息列表滚动到底部
		faceBoardView.setOnToolBoxListener(new FaceBoardView.OnToolBoxListener() {
			@Override
			public void onShowFace() {
//				ToolKits.hideInputMethod(ChatActivity.this, txtMsg);
				tempMoreUIWrapper.hide();
				listAdapter.showLastItem();
				// 按钮变为键盘模式
				btnOpenFace.setBackgroundResource(R.drawable.chat_keyboard_btn);
			}
			@Override
			public void onHideFace() {
				listAdapter.showLastItem();
				// 按钮变为表情模式
				btnOpenFace.setBackgroundResource(R.drawable.chat_face_btn);
			}
		});

		// FFF 打开表情面板
		btnOpenFace.setOnClickListener(faceBoardView.getFunctionBtnListener(1));
	}
	
	/**
	 * 初始化输入框下方的”更多“功能面板的UI
	 */
	private void initChatFunctionsUI() {
		// 实例化输入框下方的更多功能封装实现类
		this.tempMoreUIWrapper = new TMoreUIWrapperX(this, this.layoutbottomContent){
			
			/**
			 * 点击了gridview中的相应功能时将自动触发本方法。
			 * 
			 * @param actionId 相应功能的action id
			 */
			@Override
			protected void fireChatFunctionsAction(int actionId) {
				if(checkIsMyFriend())
					return;

				switch(actionId) {
					case MORE_ACTION_ID_IMAGE:
						menuWindowForSendPic.doChoosePhoto();
						this.hide(); // 处理完点击事件后即可关闭更多功能布局
						break;
					case MORE_ACTION_ID_PHOTO:
						menuWindowForSendPic.doTakePhoto();
						this.hide(); // 处理完点击事件后即可关闭更多功能布局
						break;
					case MORE_ACTION_ID_FILE: {
						SendFileHelper.openFileChooser(self());
						this.hide(); // 处理完点击事件后即可关闭更多功能布局
						break;
					}
					case MORE_ACTION_ID_SHORTVIDEO: {
						// 开始动态权限申请（用于targetSDKVersion>=23，即Android6.0及以上系统时）
						PermissionManager.requestPermission_CAMERA_$_RECORD_AUDIO(self()
								// 权限获取成功或已经取得此权限时（进入短视频录制界面）
								, (o, arg) -> ActivityCompat.startActivityForResult(self(), IntentFactory.createShortVideoRecordActivityIntent(self()), ActivityRequestCode.SHORTVIDEO_RECORD_RESULT_FROM_ACTIVITY, null)
								, null);

						this.hide(); // 处理完点击事件后即可关闭更多功能布局
						break;
					}
					case MORE_ACTION_ID_CARD_FRIEND: {
//						Intent i = IntentFactory.createUserChooseActivityIntent(TempChattingActivity.this
//								, TargetChooseActivity.USED_FOR_SEND_CONTACT_MESSAGE, Const.CHAT_TYPE_GUEST$CHAT, tempChatUIDForInit);
						Intent i = IntentFactory.createTargetChooseActivityIntent(self()
								, TargetSource.friend, null, TargetSourceFilterFactory.createTargetSourceFilter4UserContact(chatType, toId), null, null);
						ActivityCompat.startActivityForResult(self(), i, ActivityRequestCode.REQUEST_CODE_FOR_CONTACT_TARGET_CHOOSE, null);
						this.hide(); // 处理完点击事件后即可关闭更多功能布局
						break;
					}
					case MORE_ACTION_ID_CARD_GROUP: {
						Intent i = IntentFactory.createTargetChooseActivityIntent(self(), TargetSource.group, null, null, null, null);
						ActivityCompat.startActivityForResult(self(), i, ActivityRequestCode.REQUEST_CODE_FOR_CONTACT_TARGET_CHOOSE, null);

						// 处理完点击事件后即可关闭更多功能布局
						this.hide();
						break;
					}
					case MORE_ACTION_ID_LOCATION: {
						Intent intent = IntentFactory.createGetLocationActivityIntent(TempChattingActivity.this);
						ActivityCompat.startActivityForResult(self(), intent, ActivityRequestCode.REQUEST_CODE_FOR_GETTION, null);
						this.hide(); // 处理完点击事件后即可关闭更多功能布局
						break;
					}
				}
			}
		};
	}
	
	/**
	 * 初始化输入框下方的”更多“功能按钮、面板等事件处理逻辑.
	 */
	private void initChatFunctionsLisnter()
	{
		//* "+"号按钮事件处理
		btnOpenPlusFunctions.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				// 尝试关闭输入法（如果输入法已开启，无条件关闭之）
				ToolKits.hideInputMethod(self(), txtMsg);
				// 尝试关闭表情面板
				faceBoardView.hideLayout();

				// "+"号对应的内容面板当前未显示时（接下来应该被显示）
				if(!tempMoreUIWrapper.isShowing()) {
					// 延迟一会，让键盘先隐藏再显示内容面板，否则会有一瞬间内容面板和软键盘同时显示的ui跳动
					layoutbottomContent.postDelayed(() -> {
						switchBottomContent();
					}, 50);
				} else {
					switchBottomContent();
				}
			}

			private void switchBottomContent() {
				// 打开或关闭更多功能面板
				tempMoreUIWrapper.auto();
				// 消息列表首先自动滚动到最后一行
				listAdapter.showLastItem();
			}
		});

		//* 点击消息输入文本框时强制隐藏”更多“功能面板（如果它正在显示的话）
		txtMsg.setOnClickListener(v -> {
			// 消息列表首先自动滚动到最后一行
			listAdapter.showLastItem();
			// 关闭表情面板
			faceBoardView.hideLayout();
			// 当触发输入框时无条件关闭“更多”面板
			tempMoreUIWrapper.hide();
		});
		
		//* 消息输入文本框获得焦点时隐藏”更多“功能面板（如果它正在显示的话）
		txtMsg.setOnFocusChangeListener((v, hasFocus) -> {
			if (hasFocus) {
				// 关闭表情面板
				faceBoardView.hideLayout();
				// 当输入框获点输入焦点时无条件关闭“更多”面板
				tempMoreUIWrapper.hide();
			}
		});
		
		//* 消息输入文本框中有内容或无内容时隐藏或显示”更多“功能按针（如果它正在显示的话）
		txtMsg.addTextChangedListener(new TextWatcher() {             
			@Override    
			public void onTextChanged(CharSequence s, int start, int before, int count){    
				autoSwitchSendAndPlusBtn();
			}    

			@Override    
			public void beforeTextChanged(CharSequence s, int start, int count,int after) {     
				autoSwitchSendAndPlusBtn();
			}    

			@Override    
			public void afterTextChanged(Editable s) {     
				autoSwitchSendAndPlusBtn();
			}   

			// 如果消息文本框中有文本时设置消息”发送“按钮可见、”更多“功能按钮不可见，否则相反
			private void autoSwitchSendAndPlusBtn() {
				String txt = txtMsg.getText().toString();
				if (txt != null && txt.length() > 0) {
					btnSend.setVisibility(View.VISIBLE);
					btnOpenPlusFunctions.setVisibility(View.GONE);
				} else {
					btnSend.setVisibility(View.GONE);
					btnOpenPlusFunctions.setVisibility(View.VISIBLE);
				}
			}
		});  
		
		//*聊天列表listview的触摸事件(当上下滑动消息列表时)：
		// 1) 无条件关闭“更多”面板，就像微信一样；
		// 2) 如果输入法已开启，无条件关闭之，就像微信一样。
		listView.setOnTouchListener((v, event) -> {
			switch (event.getAction()) {
				case MotionEvent.ACTION_DOWN:
				case MotionEvent.ACTION_UP:
				case MotionEvent.ACTION_MOVE: {
					// 如果输入法已开启，无条件关闭之，就像微信一样
					ToolKits.hideInputMethod(TempChattingActivity.this, txtMsg);
					// 当上下滑动消息列表时无条件关闭“更多”面板，就像微信一样
					tempMoreUIWrapper.hide();
					// 关闭表情面板
					faceBoardView.hideLayout();
					break;
				}
			}
			return false;
		});
	}
	
	/**
	 * 初始化与该陌生人的聊天相关设置.
	 */
	private void initToGuest()
	{
		// 显示昵称
		this.viewNickName.setText(tempChatFriendName);
	
		// 当用户收到新消息时是通过通知观察者来刷新聊天界面中的ui显示的（从而保证显示最新消息）
		chattingDatasObserver = createChattingDatasObserver();
		// 切换到该用户的聊天记录
		chattingDatas = imc().getMessagesProvider().getMessages(this, tempChatUIDForInit);
		// 设置观察者
        chattingDatas.addObserver(chattingDatasObserver);

		// 设置聊天列表的数据模型对象
		listAdapter.setListData(chattingDatas.getDataList());
		// 刷新列表ui显示
		listAdapter.notifyDataSetChanged();

		// true表示高亮成功（高亮当前用于从搜索功能中进入到聊天界面中，从而让搜索到的消息高亮显示并自将将该条滚动到列表可视区）
		boolean highlightOnceMessage = doHighlightOnceMessage(listView);
		// 当高亮不成功时，就自动滚到最后一行
		if(!highlightOnceMessage) {
			// 自动滚动到最后一行
			listAdapter.showLastItem();
		}
	}

	/**
	 * 创建收到新消息的观察者。
	 * <p>
	 * 本观察者的作用是：用于当收到用户消息时，能由消息监督听者通知此观察者来完成ui的刷新（这样就能保证最新消息能即时显示在界面上了）。
	 *
	 * @return 观察者对象
	 */
	private ObserverMain createChattingDatasObserver(){
		return new ObserverMain() {//3
			@Override
			public void updateInMain(Observable observable, Object data) {//2

				listAdapter.notifyDataSetChanged();

				if (data != null) {
					ArrayListObservable.UpdateDataToObserver<Message> udto = (ArrayListObservable.UpdateDataToObserver<Message>) data;

					// 添加到聊天界面中的是"我"自已发出的消息
					if (udto.getExtraData() != null && udto.getExtraData().isOutgoing()) {
						// 自动让消息列表滚动到最后一行（不然会挡住自已新发的消息，影响体验哦）
						if (listAdapter != null)
							listAdapter.showLastItem();
					} else {
						// 【消息列表最后一条不可见时的处理1】当消息列表的最后不处于可见状态时（通常此时是由用户滑道列表上的面看历史消息了）
						if (!listAdapter.isLastItemVisible()) {
							if (udto != null && udto.getUpdateType() == ArrayListObservable.UpdateTypeToObserver.add) {
								// 新消息作为未读消息提示用户（有几条新消息未读——即有几条未读的正处于末尾的不可见状态）
								if (unreadMessageBallonWrapper != null)
									unreadMessageBallonWrapper.addUnreadCount(1);
							}
						}
						// 最后一条可见时，则无条件保证自动滚动到最后一行
						else {
							if (listAdapter != null)
								listAdapter.showLastItem();
						}
					}
				}
			}//2
		};//3
	}

	/**
	 * 大文件上传任务状态改变观察者.
	 *
	 * @return
	 */
	private ObserverMain createFileStatusChangedObserver() {
		return new ObserverMain() {
			@Override
			public void updateInMain(Observable observable, Object data) {
				// 收到状态改变通知就直接刷新消息列表UI
				listAdapter.notifyDataSetChanged();
			}
		};
	}

    /**
     * 逆初始化与该陌生人的聊天相关设置.
     * <p>
     * 本方法在资源回收时调用，是方法 {@link #initToGuest()} 的逆方法.
     *
     * @param tempChatUIDForInit
     */
    private void deInitToGuest(String tempChatUIDForInit) {
        // 切换到该用户的聊天记录
        chattingDatas = imc().getMessagesProvider().getMessages(this, tempChatUIDForInit);
		// 取消数据观察者
        if (chattingDatas != null && chattingDatasObserver != null) {
			chattingDatas.removeObserver(chattingDatasObserver);
        }
    }

	/**
	 * 默认将聊天文本框中的内容作为发送内分给好友.
	 */
	protected void sendPlainTextMessage(Observer sucessObs) {
		sendPlainTextMessage(txtMsg.getText().toString(), sucessObs);
	}

	public void sendPlainTextMessage(String message, Observer sucessObs) {
        TMessageHelper.sendPlainTextMessageAsync(this, tempChatUIDForInit, tempChatFriendName, message, sucessObs);
	}

	private boolean checkIsMyFriend() {
		boolean is = false;
		if(isMyFriend()) {
			// 如果输入法已开启，无条件关闭之
			ToolKits.hideInputMethod(self(), txtMsg);
			// 确认
			WidgetUtils.areYouSure(this
					, MessageFormat.format($$(R.string.temp_chat_has_already_be_friend_confirm), tempChatFriendName)
					, $$(R.string.temp_chat_has_already_be_friend_confirm_title)
					, obj -> {gotoFriendChatting();finish();}
					, null);

			is = true;
		}

		return is;
	}

	private boolean isMyFriend() {
		return imc().getFriendsListProvider().isUserInRoster2(tempChatUIDForInit);
	}

	private void gotoFriendChatting() {
		// 进入与该好友的聊天模式（界面）
		startActivity(IntentFactory.createChatIntent(this, tempChatUIDForInit));
	}


	/**
	 * 处理Acvitity的回调.
	 * {@inheritDoc}
	 */
	public void onActivityResult(int requestCode, int resultCode, Intent data) {
		super.onActivityResult(requestCode, resultCode, data);

		// 注意：此处的requestCode不要跟其它类里的冲突哦！！！！
		if (requestCode == ActivityRequestCode.TAKE_BIG_PICTURE
				|| requestCode == ActivityRequestCode.CHOOSE_BIG_PICTURE2)
			menuWindowForSendPic.onParantActivityResult(requestCode, resultCode, data);
		else if (requestCode == ActivityRequestCode.CHOOSE_FILE_RESULT_FROM_ACTIVITY) {
			SendFileHelper.onParantActivityResult(this, requestCode, resultCode, data
					, Const.CHAT_TYPE_GUEST$CHAT, tempChatUIDForInit, tempChatFriendName);
		}
		// 短视频录制完成后的回调
		else if (requestCode == ActivityRequestCode.SHORTVIDEO_RECORD_RESULT_FROM_ACTIVITY) {
			super.onActivityResult_shortVideoRecordComplete(data);
		}
		// "名片"消息时，选择要发送的用户或群的回调
		else if (requestCode == ActivityRequestCode.REQUEST_CODE_FOR_CONTACT_TARGET_CHOOSE) {
			super.onActivityResult_contactTargetSelectedComplete(this, listAdapter, data);
		}
		// 消息转发时，选择转发接收者（用户或群）后的回调
		else if (requestCode == ActivityRequestCode.REQUEST_CODE_FOR_FORWARD_TARGET_CHOOSE) {
			super.onActivityResult_forwardTargetSelectedComplete(this, listAdapter, data);
		}
		// "位置"消息时，选择要发送的位置的回调
		else if (requestCode == ActivityRequestCode.REQUEST_CODE_FOR_GETTION) {
			super.onActivityResult_locationSelectedComplete(this, data);
		} else {
			// do nothing
		}
	}

	/**
	 * 刷新聊天列表。
	 */
	@Override
	protected void  notifyListDataSetChanged(){
		this.listAdapter.notifyDataSetChanged();
	}


    //----------------------------------------------------------------- 以下为内部类

	/**
	 * 自定义陌生人(临时)聊天消息列表的adapter类实现.
	 */
	private class TempChattingListAdapter extends AbstractChattingListAdapter {
		public TempChattingListAdapter(Activity context, ListView theListViewBtContact, String tempChatUIDForInit) {
			super(context, theListViewBtContact, tempChatUIDForInit, false);// true
		}
		
		/**
		 * 图片消息的图片上传到服务端（用于暂存和中转）成功后即发送一条消息给聊天的对方.
		 * 
		 * @param msgType MsgType
		 * @param fingerPring
		 */
		@Override
		protected void sendImageOrVoiceMessageAsyncImpl(int msgType, boolean isOutgoing, String imageOrVoiceFileName, String fingerPring) {
			if (isOutgoing) {
				if (msgType == MsgType.TYPE_IMAGE)
					// 并发送一条图片消息给好友（之前图片已成功上传到服务端罗！）
					TMessageHelper.sendImageMessageAsync((Activity) context, tempChatUIDForInit, tempChatFriendName, imageOrVoiceFileName, fingerPring, null);
				else if (msgType == MsgType.TYPE_VOICE)
					// 并发送一条图片消息给好友（之前图片已成功上传到服务端罗！）
					TMessageHelper.sendVoiceMessageAsync((Activity) context, tempChatUIDForInit, tempChatFriendName, imageOrVoiceFileName, fingerPring, null);
			}
		}
		
		@Override
		protected ArrayListObservable<Message> getChattingDatas() {
			return chattingDatas;
		}

        /**
         * 当列表滑到最后一行时将调用的方法.
         */
        @Override
        protected void onScrollToBottom() {
            if(unreadMessageBallonWrapper != null)
                // 【当消息列表真滑动到最后一条可见时的处理3】设置“未读数”提示UI不可见（重置未读数为0）
                unreadMessageBallonWrapper.resetUnreadCount();
        }

        /**
         * 消息重发实现方法。
         * 子类需实现本方法，从而实现消息的重发逻辑。
         *
         * @param entity
         */
        @Override
        protected void reSendImpl(Message entity) {
			if(entity.isForwardOutgoing()) {
				TMessageForwardHelper.forward((Activity) context, entity, tempChatUIDForInit, tempChatFriendName, null);
			} else {
				TMessageReSendHelper.reSend((Activity) context, entity, tempChatUIDForInit, tempChatFriendName);
			}
        }
	}
}
